/*
********************************************************************************
 Title:	AddResM
 Author:	Paul Clifford
		Modified Philip Ludlam
 Copyright:	(C) Paul Clifford 1995
 Version:	1.00, 1 Dec 1995
 Purpose:	Adds a file/directory to ResourceFS

 Modified by:	Philip Ludlam
 Changes:	Made it 32-bit compatible
		Fixed bugs in 32-bit conversion.
		Optimised the module.
		Added facility to add a single file.
 Version	1.05, 4 September 2003

********************************************************************************
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the Free
 Software Foundation; either version 2 of the License, or (at your option)
 any later version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR APARTICULAR PURPOSE. See the GNU General Public License for more
 details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place - Suite 330, Boston, MA 02111-1307, USA

********************************************************************************
*/

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "oslib/os.h"
#include "oslib/osfile.h"
#include "oslib/osgbpb.h"
#include "oslib/osmodule.h"
#include "oslib/osword.h"
#include "oslib/territory.h"

#define SYNTAX_ERROR "Syntax: AddRes -path <Resources path> -include \
<directory/file> -title <module title> [-save <filename>]\n"
#define KEYWORDS "path/k/a,include/k/a,title/k/a,save/k"

// *****************************************************************************

typedef void (function) (const char*, const char*);

struct
{   char* path;
    char* include;
    char* title;
    char* save;
    char data[1024];
} parameters;

struct
{   bits load_address;
    bits execution_address;
    int size;
    fileswitch_attr attributes;
    fileswitch_object_type object_type;
    char name[256];
} file;

byte* resource_data;
int resource_data_size;
int resource_data_offset;

void scan_path(const char*, function*);
void calculate_size(const char*, const char*);
void include_file(const char*, const char*);
void fail(char*, ...);

extern int Module_Start;
extern int Module_End;

// *****************************************************************************


int main(void)
{   char* input;
    char* module_text;
    os_date_and_time utc;
    int Module_Size = (&Module_End - &Module_Start) * 4;

    input = strchr(os_get_env(NULL, NULL), '-');
    if (!input) fail(SYNTAX_ERROR);
    if (xos_read_args(KEYWORDS, input, (char*) &parameters, sizeof(parameters), NULL)) fail(SYNTAX_ERROR);

    resource_data_size = Module_Size + strlen(parameters.title) + strlen(parameters.title) + 21;
    scan_path(parameters.include, calculate_size);
    resource_data_size += 4;

    resource_data = osmodule_alloc(resource_data_size);
    memcpy(resource_data, &Module_Start, Module_Size);
    resource_data_offset = Module_Size;
    scan_path(parameters.include, include_file);

    ((int*) resource_data)[resource_data_offset / 4] = 0;
    ((int*) resource_data)[4] = resource_data_offset + 4;
    ((int*) resource_data)[5] = resource_data_offset + strlen(parameters.title) + 5;
    module_text = (char*) resource_data + resource_data_offset + 4;
    sprintf(module_text, "%s", parameters.title);
    module_text += strlen(parameters.title) + 1;
    sprintf(module_text, "%s\t1.00 (", parameters.title);
    module_text += strlen(parameters.title) + 7;
    sprintf(module_text, "01 Dec 1995");
    utc[0] = 3;
    oswordreadclock_utc((oswordreadclock_utc_block*) &utc);
    territory_convert_date_and_time(-1, &utc, module_text, 12, "%dy %m3 %ce%yr");
    module_text += 11;
    sprintf(module_text, ")");

    if (parameters.save)
    {   osfile_save_stamped(parameters.save, 0xffa, resource_data, resource_data + resource_data_size);
    	osmodule_free(resource_data);
    }
    else
    	osmodule_add_area(resource_data);

    return(0);
}

void scan_path(const char* directory, function* call)
{   int context = 0;
    int read_count;
    char buffer[256];
    os_error *err;

    if ((err = xosfile_read_no_path(directory, &file.object_type,
        &file.load_address, &file.execution_address, &file.size,
        &file.attributes)) != NULL) {
      fprintf (stderr, "AddRes: Unable to stat '%s'.\n", directory);
      exit (0);
    }

    if (file.object_type == fileswitch_NOT_FOUND) {
      fprintf (stderr, "AddRes: No such file file or directory '%s'.\n", directory);
      exit (0);
    } else if (file.object_type == 1) {
      char *dot;
      if ((dot = strrchr(directory, '.')) != NULL) {
        char *filename = (char*) (1 + (int) dot);
        *dot = '\0';
        call(directory, filename);
        *dot = '.';
      } else {
        call ("@.", directory);
      }
   } else {
      context = osgbpb_dir_entries_info(directory, (osgbpb_info_list*) &file, 1, context, sizeof(file), "*", &read_count);
      while (read_count) {
        if (file.object_type == 1)
          call(directory, file.name);
        else if (file.object_type == 2 || file.object_type == 3) {
          sprintf(buffer, "%s.%s", directory, file.name);
          scan_path(buffer, call);
        }
        context = osgbpb_dir_entries_info(directory, (osgbpb_info_list*) &file, 1, context, sizeof(file), "*", &read_count);
      }
    }
}

void calculate_size(const char* directory, const char* leaf_name)
{   char* path = (char*) (directory + strlen(parameters.include));
    int filename_length;
    int file_data_size = (file.size + 3) & ~3;

    filename_length = (strlen(parameters.path) + strlen(path) + strlen(leaf_name) + 2 + 3) & ~3;
    resource_data_size += filename_length + file_data_size + 24;
}

void include_file(const char* directory, const char* leaf_name)
{   char* path = (char*) (directory + strlen(parameters.include));
    int filename_length;
    int file_data_size = (file.size + 3) & ~3;
    char resource_filename[256];
    char real_filename[256];
    byte* byte_data = resource_data + resource_data_offset;
    int* int_data = (int*) byte_data;

    filename_length = (strlen(parameters.path) + strlen(path) + strlen(leaf_name) + 2 + 3) & ~3;
    sprintf(resource_filename, "%s%s.%s", parameters.path, path, leaf_name);
    sprintf(real_filename, "%s.%s", directory, leaf_name);
    int_data[0] = 24 + filename_length + file_data_size;
    int_data[1] = file.load_address;
    int_data[2] = file.execution_address;
    int_data[3] = file.size;
    int_data[4] = file.attributes;
    int_data[(filename_length / 4) + 5] = file.size + 4;
    strcpy((char*) (byte_data + 20), resource_filename);
    osfile_load_stamped_no_path(real_filename, byte_data + 20 + filename_length + 4, NULL, NULL, NULL, NULL);

    resource_data_offset += filename_length + file_data_size + 24;
}

void fail(char* error, ...)
{   va_list ap;

    va_start(ap, error);
    vfprintf(stderr, error, ap);
    va_end(ap);
    exit(1);
}
